; Copyright (C) 1998-2004 Elliott Hughes <enh@jessies.org>
;               2004 Stefan Bellon <sbellon@sbellon.de>
;
; This file is part of JetDirectFS.
;
; JetDirectFS is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; JetDirectFS is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA

r0      RN      0
r1      RN      1
r2      RN      2
r3      RN      3
r4      RN      4
r5      RN      5
r6      RN      6
r7      RN      7
r8      RN      8
r9      RN      9
r10     RN     10
r11     RN     11
r12     RN     12
r13     RN     13
r14     RN     14
r15     RN     15

a1      RN      0
a2      RN      1
a3      RN      2
a4      RN      3

v1      RN      4
v2      RN      5
v3      RN      6
v4      RN      7
v5      RN      8
v6      RN      9

sl      RN     10
fp      RN     11
ip      RN     12
sp      RN     13
lr      RN     14
pc      RN     15

C_bit   *       1 :SHL: 29
V_bit   *       1 :SHL: 28

        IMPORT  |Image$$RO$$Base|
        IMPORT  |_Lib$Reloc$Off$DP|
        IMPORT  fsentry_open
        IMPORT  fsentry_getbytes
        IMPORT  fsentry_putbytes
        IMPORT  fsentry_args
        IMPORT  fsentry_close
        IMPORT  fsentry_file
        IMPORT  fsentry_func
        IMPORT  fsentry_gbpb

        EXPORT  veneer_fsentry_open
        EXPORT  veneer_fsentry_getbytes
        EXPORT  veneer_fsentry_putbytes
        EXPORT  veneer_fsentry_args
        EXPORT  veneer_fsentry_close
        EXPORT  veneer_fsentry_file
        EXPORT  veneer_fsentry_func
        EXPORT  veneer_fsentry_gbpb

        AREA    FSEntry_Interfaces,REL,CODE,READONLY

        LTORG

veneer_fsentry_open
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*0
        B       fsentry_common
veneer_fsentry_getbytes
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*1
        B       fsentry_common
veneer_fsentry_putbytes
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*2
        B       fsentry_common
veneer_fsentry_args
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*3
        B       fsentry_common
veneer_fsentry_close
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*4
        B       fsentry_common
veneer_fsentry_file
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*5
        B       fsentry_common
veneer_fsentry_func
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*6
        B       fsentry_common
veneer_fsentry_gbpb
        STMFD   sp!, {r8}
        MOV     r8, #fsentry_branchtable - %F10 + 4*7
        B       fsentry_common

fsentry_common  ; os_error *fsentry_common( Parameter_Block * )

        ; Store the input registers onto the stack
        STMFD   sp!,{r0-r7, sl, fp, ip, lr}

        MOV     sl, sp, LSR #20
        MOV     sl, sl, LSL #20         ; SP_LWM
        LDMIA   sl, {v1, v2}            ; save old reloc modifiers over fn call
        LDR     r12, [r12]              ; private word pointer
        LDMIB   r12, {fp, r12}          ; new relocation modifiers
        STMIA   sl,  {fp, r12}          ; set by module init
        MOV     fp, #0                  ; halt C backtrace here!

        ; This is equivalent of 'ADD r10, r10, #0' + |_Lib$Reloc$Off$DP|
        DCD     |_Lib$Reloc$Off$DP| + &E28AA000

        ; Pass a pointer to the structure on the stack
        MOV     a1, sp

        ; BL    fsentry_branchtable[r8]
        MOV     lr, pc
        ADD     pc, pc, r8

        ; This is equivalent of 'SUB r10, r10, #0' + |_Lib$Reloc$Off$DP|
        DCD     |_Lib$Reloc$Off$DP| + &E24AA000

10      ; This label must be the 2nd instructions past the above ADD pc, pc, r8

        STMIA   sl, {v1, v2}            ; restore old reloc modifiers

        ; 32-bit and 26-bit have different code (it's easier to split)
        TEQ     r0, r0
        TEQ     pc, pc
        BEQ     ret_32bit

        ; 26-bit code from here on

        ; Save the returned value in r8
        MOVS    r8, r0
        ; Get the stuff off the stack
        LDMFD   sp!, {r0-r7, sl, fp, ip, lr}
        ; If returned value indicates an error, then set the overflow and put it back in r0
        MOVNE   r0, r8

        ; Mess about with the flag bits in r8
        MOV     r8, pc
        BIC     r8, r8, #C_bit + V_bit
        ORRNE   r8, r8, #V_bit          ; V = err != 0
        TST     r1, r1                  ; C = r1 == 0
        ORREQ   r8, r8, #C_bit

        ; Move the flag bits into psr
        TEQP    r8, #0

        LDMFD   sp!, {r8}

        MOV     pc, lr

        ; 32-bit code from here on
ret_32bit
        ; Save the returned value in r8
        MOVS    r8, r0
        ; Get the stuff off the stack
        LDMFD   sp!, {r0-r7, sl, fp, ip, lr}
        ; If returned value indicates an error, then set the overflow and put it back in r0
        MOVNE   r0, r8

        ; Mess about with the flag bits in r8
        MRS     r8, cpsr
        BIC     r8, r8, #C_bit + V_bit
        ORRNE   r8, r8, #V_bit          ; V = err != 0
        TST     r1, r1                  ; C = r1 == 0
        ORREQ   r8, r8, #C_bit

        ; Move the flag bits into psr
        MSR     cpsr_f, r8

        LDMFD   sp!, {r8}

        MOV     pc, lr

fsentry_branchtable
        B       fsentry_open
        B       fsentry_getbytes
        B       fsentry_putbytes
        B       fsentry_args
        B       fsentry_close
        B       fsentry_file
        B       fsentry_func
        B       fsentry_gbpb

        END
